﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Messaging;

using System.Runtime.Remoting;
using System.Reflection;
using System.Diagnostics;

namespace MessageCallAspect.Inspector.MessageSink
{
    public abstract class BaseMessageSink : IMessageSink
    {
        private readonly IMessageSink m_NextSink;
        private readonly IModuleContext m_Context;

        #region ctor

        public BaseMessageSink(IModuleContext context, IMessageSink nextSink)
        {
            m_Context = context;
            m_NextSink = nextSink;
        }

        #endregion

        protected virtual IModuleContext Context
        {
            get
            {
                return m_Context;
            }
        }

        #region IMessageSink Members

        public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
        {
            throw new NotImplementedException();
        }

        public virtual IMessageSink NextSink
        {
            get
            {
                return m_NextSink;
            }
        }
        
        public IMessage SyncProcessMessage(IMessage msg)
        {
            Debug.WriteLine("Step into: "+this.GetType().Name);
            BeforeInvoke(msg);
            IMessage returnMethod = null;
            try
            {
                returnMethod = NextSink.SyncProcessMessage(msg);
                Debug.WriteLine("Step into: " + this.GetType().Name);
                Exception ex = ((ReturnMessage)returnMethod).Exception;
                if (ex != null)
                {
                    ExceptionHandling(returnMethod, ex);
                }
            }
            catch (Exception ex)
            {
                ExceptionHandling(msg, ex);
            }
            finally
            {
                AfterInvoke(msg, returnMethod);
            }
            return returnMethod;
        }

        #endregion

        protected virtual void BeforeInvoke(IMessage msg)
        {
        }

        protected virtual void AfterInvoke(IMessage msg, IMessage returnMethod)
        {
        }

        protected virtual Exception OnException(IMessage msg, Exception ex)
        {
            return ex;
        }

        private IMessage ExceptionHandling(IMessage msg, Exception ex)
        {
            IMessage returnMethod = msg;
            Exception newException = OnException(msg, ex);
            if (!object.ReferenceEquals(ex, newException))
            {
                returnMethod = ex.Wrap(msg);
            }

            return returnMethod;
        }
    }
    
}
